package gestiontienda.dataaccess.base.hibernate;


import gestiontienda.dataaccess.base.GenericDAO;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 *
 * @author pcmd05b
 */
public class HibernateGenericDAO <T, ID extends Serializable> implements GenericDAO<T,ID> {
    private HibernateAdaptee adaptee = new HibernateAdaptee();
    private Class<T> persistentClass;

    public HibernateAdaptee getAdaptee() {
        return adaptee;
    }

    public void setAdaptee(HibernateAdaptee adaptee) {
        this.adaptee = adaptee;
    }


    public HibernateGenericDAO(Class<T> persistentClass){
        this.persistentClass = persistentClass;
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }


    public void delete(final T entity) {
        adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.delete(entity);
                return null;
            }
        });
    }

    public List<T> executeQuery(final String queryString) {

        return adaptee.getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(queryString);
                List list = query.list();
                return list;
            }
        });
    }

    public List<T> executeSQLQuery(final String queryString) {

        return adaptee.getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(queryString);
                query.addEntity(persistentClass);
                List list = query.list();
                return list;
            }
        });
    }

    public List<T> findbyCriterion(final Criterion... criterions) {

        return adaptee.getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {

                Criteria criteria = session.createCriteria(getPersistentClass());
                criteria.add(Restrictions.disjunction() );
                for (Criterion criterion : criterions) {
                    criteria.add(criterion);
                }
                List result = criteria.list();
                return result;
            }
        });
    }


    public List<T> findbyNamedParam(final String query, final String[] named, final Object[] values) {

        return adaptee.getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                List list = adaptee.getHibernateTemplate().findByNamedParam(query,named, values);
                return  list;
            }
        });
    }

    public List<T> findbyNamedOneParam(final String query, final String named, final Object values) {

        return  adaptee.getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                List list = adaptee.getHibernateTemplate().findByNamedParam(query,named, values);
                return  list;
            }
        });
    }



    public T get(final ID id) {

        return (T) adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Object obj = session.get(persistentClass,id);
                return obj;
            }
        });
    }


    public ID insert(final T entity) {

        return(ID) adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                    Serializable id = session.save(entity);
                    return id;
            }
        });
    }


    public T merge(final T entity) {

        return (T) adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.setFlushMode(FlushMode.AUTO);
                return session.merge(entity);
            }
        });
    }


    public void saveOrUpdate(final T entity) {

        adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.saveOrUpdate(entity);
                //session.flush();
                //session.close();
                return null;
            }
        });
    }


    public void update(final T entity) {

        adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.update(entity);
                return null;
            }
        });
    }


    public List<T> getAll() {
        return findbyCriterion();
    }


    public int deleteById(final ID id) {
        return (Integer) adaptee.getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {

				int affectedRecords = session.createQuery(
									"delete from " + getPersistentClass().getSimpleName() + " where id = ?")
									.setParameter(0, id)
									.executeUpdate();
				return affectedRecords;
			}
		});

    }

    public List<T> listByCriteria(DetachedCriteria c) {
        return adaptee.getHibernateTemplate().findByCriteria(c);
    }

    //Para Auditoria

    @Override
    public void auditSave(final T entity) {
        adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.saveOrUpdate(entity);
                return null;
            }
        });
    }

    @Override
    public void auditUpdate(final T entity) {
        adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.update(entity);
                return null;
            }
        });
    }

    @Override
    public T auditMerge(final T entity) {
        return (T) adaptee.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.setFlushMode(FlushMode.AUTO);
                return session.merge(entity);
            }
        });
    }
}